package com.demo.webapp.kcfinder;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

/**
 * 默认ActionMapping生成器
 * 
 * @author ryuu.kk
 *
 */
public abstract class DefaultActionMappingBuilder implements ActionMappingBuilder {

	/**
	 * 默认扩展名
	 */
	public final static String DEFAULT_EXTENSION = "kc";
	
	protected List<String> extensions = new ArrayList<String>() {
		/** serialVersionUID **/
		private static final long serialVersionUID = 6607398437727687434L;
	{
		//add("");
		add(DEFAULT_EXTENSION);
	}};
	
    public static String getServletPath(HttpServletRequest request) {
        String servletPath = request.getServletPath();
        
        String requestUri = request.getRequestURI();
        // Detecting other characters that the servlet container cut off (like anything after ';')
        if (requestUri != null && servletPath != null && !requestUri.endsWith(servletPath)) {
            int pos = requestUri.indexOf(servletPath);
            if (pos > -1) {
                servletPath = requestUri.substring(requestUri.indexOf(servletPath));
            }
        }
        
        if (null != servletPath && !"".equals(servletPath)) {
            return servletPath;
        }
        
        int startIndex = request.getContextPath().equals("") ? 0 : request.getContextPath().length();
        int endIndex = request.getPathInfo() == null ? requestUri.length() : requestUri.lastIndexOf(request.getPathInfo());

        if (startIndex > endIndex) { // this should not happen
            endIndex = startIndex;
        }

        return requestUri.substring(startIndex, endIndex);
    }

	protected void parseNameAndNamespace(String uri, ActionMapping mapping) {
		String namespace, name;
		int lastSlash = uri.lastIndexOf("/");
		if (lastSlash == -1) {
			namespace = "";
			name = uri;
		} else if (lastSlash == 0) {
			// ww-1046, assume it is the root namespace, it will fallback to
			// default
			// namespace anyway if not found in root namespace.
			namespace = "/";
			name = uri.substring(lastSlash + 1);
		} else {
			// Simply select the namespace as everything before the last slash
			namespace = uri.substring(0, lastSlash);
			name = uri.substring(lastSlash + 1);
		}

		if (name != null) {
			int pos = name.lastIndexOf('/');
			if (pos > -1 && pos < name.length() - 1) {
				name = name.substring(pos + 1);
			}
		}

		mapping.setNamespace(namespace);
		mapping.setName(name);
	}

	@Override
	public String getMappingUri(ActionMapping mapping) {
		StringBuilder uri = new StringBuilder();

		if (mapping.getNamespace() != null) {
			uri.append(mapping.getNamespace());
			if (!"/".equals(mapping.getNamespace())) {
				uri.append("/");
			}
		}
		String name = mapping.getName();
		uri.append(name);

		if (null != mapping.getMethod() && !"".equals(mapping.getMethod())) {
			uri.append("!").append(mapping.getMethod());
		}

		String extension = mapping.getExtension();
		if (extension == null) {
			extension = getDefaultExtension();
		}

		if (extension != null) {
			if (extension.length() == 0
					|| (extension.length() > 0 && uri.indexOf('.' + extension) == -1)) {
				if (extension.length() > 0) {
					uri.append(".").append(extension);
				}
			}
		}
		
		String params = "";
//		if (name.indexOf('?') != -1) {
//			params = name.substring(name.indexOf('?'));
//			name = name.substring(0, name.indexOf('?'));
//		}
		Map<String, Object> paramsMap = mapping.getParams();
		if (!paramsMap.isEmpty()) {
			Set<String> keySet = paramsMap.keySet();
			Iterator<String> keyIterator = keySet.iterator();
			while(keyIterator.hasNext()) {
				String key = keyIterator.next();
				params += key + "=" + paramsMap.get(key) + "&";
			}
		}
		if (params.length() > 0) {
			params = "?" + params.substring(0, params.lastIndexOf("&") - 1);
			uri.append(params);
		}

		return uri.toString();
	}
	
	protected String getDefaultExtension() {
		return DEFAULT_EXTENSION;
	}
	
	/**
	 * 通过扩展名判断请求是否由ActionMappingBuilder对象所支持
	 * @param request HttpServletRequest
	 */
	@Override
	public ActionMapping getMapping(HttpServletRequest request) {
		ActionMapping mapping = new ActionMapping();
		String uri = getUri(request);

        int indexOfSemicolon = uri.indexOf(";");
        uri = (indexOfSemicolon > -1) ? uri.substring(0, indexOfSemicolon) : uri;

        //返回扩展名分接口的URI地址,如果扩展名不再允许的范围内,则这个URL为NULL
        uri = parseExtension(uri, mapping);
        
        if (uri == null) {
            return null;
        }

        parseNameAndNamespace(uri, mapping);
        
        return mapping;
	}
	
	protected String parseExtension(String uri, ActionMapping mapping) {
		String uritmp = uri.substring(0, uri.indexOf("?") != -1 ? uri.indexOf("?") : uri.length());
		int i = uritmp.lastIndexOf(".");
		if (i == -1) {
			return null;
		}
		//取得请求的扩展名
		String extension = uritmp.substring(i + 1);
		//如果请求的扩展名是不被允许的,不对请求创建对应的ActionMapping
		boolean isAllow = false;
		for (String exten : this.extensions) {
			if ("".equals(exten) || exten.equals(extension)) {
				isAllow = true;
				break;
			}
		}
		if (!isAllow) {
			return null;
		}
		mapping.setExtension(extension);
		return uri.substring(0, i);
	}
	
    protected String getUri(HttpServletRequest request) {
        // handle http dispatcher includes.
        String uri = (String) request
                .getAttribute("javax.servlet.include.servlet_path");
        if (uri != null) {
            return uri;
        }

        uri = getServletPath(request);
        if (uri != null && !"".equals(uri)) {
            return uri;
        }

        uri = request.getRequestURI();
        return uri.substring(request.getContextPath().length());
    }
    
    protected void setExtensions(List<String> extens) {
    	this.extensions = extens;
    }
}
